From f99aa220a382dbf24afdbcb6dee154a8b0115876 Mon Sep 17 00:00:00 2001 From: Robert Lipe Date: Sun, 22 Jul 2018 00:19:50 -0500 Subject: [PATCH] Move csv & style handlers to real C++ containers Goal: eliminate lots of manual string bashing. Currently waffles between the two approaches, but I wanted to get this into GitHub for valgrind results. --- csv_util.cc | 85 +++++++++++++++++++++++++++++---------------------- csv_util.h | 18 ++++++----- gui/setup.iss | 1 + 3 files changed, 60 insertions(+), 44 deletions(-) diff --git a/csv_util.cc b/csv_util.cc index 6bfcc9349..24b31290e 100644 --- a/csv_util.cc +++ b/csv_util.cc @@ -183,8 +183,8 @@ csv_stringclean(const QString& source, const QString& to_nuke) return r.remove(QRegExp(regex)); } -// csv_stringtrim() - trim whitespace and leading and trailing -// enclosures (quotes) +// csv_stringtrim() - trim whitespace and leading and trailing +// enclosures (quotes) // returns a copy of the modified string // usage: p = csv_stringtrim(string, "\"", 0) char* @@ -243,9 +243,9 @@ csv_stringtrim(const char* string, const char* enclosure, int strip_max) return (tmp); } -// Is this really the replacement for the above? +// Is this really the replacement for the above? QString -csv_stringtrim(const QString& source, const QString& enclosure) +csv_stringtrim(const QString& source, const QString& enclosure) { QString r = source; r.replace(enclosure, ""); @@ -754,16 +754,16 @@ XcsvFile::XcsvFile() { is_internal = false; ifield_ct = ofield_ct = 0; extension = description = nullptr; -// xcsv_file_init(); +// xcsv_file_init(); } -void validate_fieldmap(field_map_t* fmp, bool is_output) { +static void validate_fieldmap(const field_map_t* fmp, bool is_output) { QString qkey = fmp->key; QString qval = fmp->val; QString qprintfc = fmp->printfc; if (qkey.isEmpty()) { - Fatal() << MYNAME << ": xcsv style is missing" << + Fatal() << MYNAME << ": xcsv style is missing" << (is_output ? "output" : "input") << "field type."; } if (!fmp->val) { @@ -779,7 +779,7 @@ void validate_fieldmap(field_map_t* fmp, bool is_output) { /* usage: xcsv_ifield_add("DESCRIPTION", "", "%s") */ /*****************************************************************************/ void -xcsv_ifield_add(char* key, char* val, char* pfc) +xcsv_ifield_add(const char* key, const char* val, const char* pfc) { field_map_t* fmp = (field_map_t*) xcalloc(sizeof(*fmp), 1); struct xt_mapping* xm = Perfect_Hash::in_word_set(key, strlen(key)); @@ -799,7 +799,7 @@ xcsv_ifield_add(char* key, char* val, char* pfc) /* usage: xcsv_ofield_add("LAT_DECIMAL", "", "%08.5lf") */ /*****************************************************************************/ void -xcsv_ofield_add(char* key, char* val, char* pfc, int options) +xcsv_ofield_add(const char* key, const char* val, const char* pfc, int options) { field_map_t* fmp = (field_map_t*) xcalloc(sizeof(*fmp), 1); struct xt_mapping* xm = Perfect_Hash::in_word_set(key, strlen(key)); @@ -928,7 +928,7 @@ writetime(const char* format, const gpsbabel::DateTime& t, bool gmt) return writetime(format, t.toTime_t(), gmt); } -QString +QString writehms(const char* format, time_t t, int gmt) { static struct tm no_time = tm(); @@ -2197,6 +2197,39 @@ xcsv_noop(const route_head* wp) /* no-op */ } +// return |original| after performing token replacement. +static QString +xcsv_replace_tokens(const QString& original) { + QString replacement = original; + // Don't do potentially expensive replacements if token prefix + // isn't present; + if (original.contains("__")) { + struct tm tm; + time_t my_time = gpsbabel_time; + if (my_time == 0) { /* testo script ? */ + tm = *gmtime(&my_time); + } else { + tm = *localtime(&my_time); + } + + replacement.replace("__FILE__", xcsv_file.fname); + replacement.replace("__VERSION__", my_time == 0 ? "" : gpsbabel_version); + + QDateTime dt = QDateTime::fromTime_t(my_time); + dt = dt.toTimeSpec(Qt::UTC); + + QString dts = dt.toString("ddd MMM dd hh:mm:ss yyyy"); + replacement.replace("__DATE_AND_TIME__", dts); + + QString d = dt.toString("MM/dd/yyyy"); + replacement.replace("__DATE__", d); + + QString t = dt.toString("hh:mm:ss"); + replacement.replace("__TIME__", t); + } + return replacement; +} + /*****************************************************************************/ /* xcsv_data_write(void) - write prologues, spawn the output loop, and write */ /* epilogues. */ @@ -2218,30 +2251,9 @@ xcsv_data_write(void) } /* output prologue lines, if any. */ - foreach(const QString& line, xcsv_file.prologue) { - // If the XCSV description contains weird characters (like sportsim) - // this is where they get lost. - QString cout = line; - - // Don't do potentially expensive replacements if token prefix - // isn't present; - if (cout.contains("__")) { - cout.replace("__FILE__", xcsv_file.fname); - cout.replace("__VERSION__", time == 0 ? "" : gpsbabel_version); - - QDateTime dt = QDateTime::fromTime_t(time); - dt = dt.toTimeSpec(Qt::UTC); - - QString dts = dt.toString("ddd MMM dd hh:mm:ss yyyy"); - cout.replace("__DATE_AND_TIME__", dts); - - QString d = dt.toString("MM/dd/yyyy"); - cout.replace("__DATE__", d); - - QString t = dt.toString("hh:mm:ss"); - cout.replace("__TIME__", t); - } - *xcsv_file.stream << cout << xcsv_file.record_delimiter; + for (auto line : xcsv_file.prologue) { + QString line_to_write = xcsv_replace_tokens(line); + *xcsv_file.stream << line_to_write << xcsv_file.record_delimiter; } if ((xcsv_file.datatype == 0) || (xcsv_file.datatype == wptdata)) { @@ -2255,8 +2267,9 @@ xcsv_data_write(void) } /* output epilogue lines, if any. */ - foreach(const QString& ogp, xcsv_file.epilogue) { - *xcsv_file.stream << ogp << xcsv_file.record_delimiter; + for (auto line : xcsv_file.epilogue) { + QString line_to_write = xcsv_replace_tokens(line); + *xcsv_file.stream << line_to_write << xcsv_file.record_delimiter; } } #endif diff --git a/csv_util.h b/csv_util.h index aeed5ce2e..47de05d2d 100644 --- a/csv_util.h +++ b/csv_util.h @@ -69,16 +69,16 @@ void xcsv_epilogue_add(char*); void -xcsv_ifield_add(char*, char*, char*); +xcsv_ifield_add(const char*, const char*, const char*); void -xcsv_ofield_add(char*, char*, char*, int options); +xcsv_ofield_add(const char*, const char*, const char*, int options); void xcsv_destroy_style(void); const char* -xcsv_get_char_from_constant_table(char* key); +xcsv_get_char_from_constant_table(const char* key); /****************************************************************************/ /* types required for various xcsv functions */ @@ -90,9 +90,9 @@ xcsv_get_char_from_constant_table(char* key); #define OPTIONS_OPTIONAL 3 typedef struct field_map { queue Q; - char* key; - char* val; - char* printfc; + const char* key; + const char* val; + const char* printfc; int hashed_key; int options; } field_map_t; @@ -132,6 +132,8 @@ class XcsvFile { queue ifield; /* input field mapping */ queue* ofield; /* output field mapping */ + QList ifields; + QList ofields; int ifield_ct; /* actual # of ifields */ int ofield_ct; /* actual # of ofields */ @@ -141,8 +143,8 @@ class XcsvFile { QTextCodec* codec; QString fname; /* ptr to filename of above. */ - char* description; /* Description for help text */ - char* extension; /* preferred filename extension (for wrappers)*/ + const char* description; /* Description for help text */ + const char* extension; /* preferred filename extension (for wrappers)*/ short_handle mkshort_handle;/* handle for mkshort() */ ff_type type; /* format type for GUI wrappers. */ diff --git a/gui/setup.iss b/gui/setup.iss index 8ed735cd4..4b8e163f5 100644 --- a/gui/setup.iss +++ b/gui/setup.iss @@ -49,6 +49,7 @@ Source: "..\{#gui_build_dir_name}\release\*"; Excludes: "app.res,vcredist_*.exe, Source: "..\{#gui_build_dir_name}\release\vcredist_x86.exe"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist deleteafterinstall Source: "..\{#gui_build_dir_name}\release\vcredist_x64.exe"; DestDir: "{app}"; Flags: ignoreversion skipifsourcedoesntexist deleteafterinstall Source: "..\..\{#gpsbabel_build_dir_name}\release\gpsbabel.exe"; DestDir: "{app}"; Flags: ignoreversion +; Source: release\help\*; DestDir: "{app}\help"; Flags: ignoreversion recursesubdirs createallsubdirs ; Translation strings extracted from source code. Include it in the dist ; so that users can translate if they want to. -- 2.30.2